package com.terrynoya.utils
{
    import flash.utils.Dictionary;

    /**
     * UzHashMap 存储键值对的表. 利用Flash Player提供的Dictionary作为内部存储.
     * 不允许使用 null或者undefined 作为键,但允许使用 null 作为值
     *
     * @author wengjiawei
     */
    public class UzHashMap
    {
        private var _dic:Dictionary;
        private var _length:int;

        /**
         * 构造函数
         */
        public function UzHashMap()
        {
            _dic = new Dictionary();
            _length = 0;
        } 

        /**
         * 添加一个键值对.key不能为null或者undefined,value可以为null. 如果表中已存在相应的key,则添加失败.
         *
         * @param key 即将添加的键
         * @param value 即将添加的值
         * @return 添加成功,则为true,添加失败则为flase
         * @throws ArgumentError 如果 key 为null或者undefined,则引发异常
         */
        public function add(key:*, value:*):Boolean
        {
            // 检查 key 是否为 null 或 undefined
            if (key == null)
            {
                throw new ArgumentError("cannot add a value with a undefined or null key");
            }

            if (_dic[key] === undefined && value !== undefined)
            {
                _dic[key] = value;
                ++_length;
                return true;
            }
            return false;
        }

        /**
         * 更新key所对应的value. key不能为null或者undefined,value可以为null. 如果表中不存在相应的key,则更新失败
         *
         * @param key 对应的键
         * @param value 需要更新的值
         * @return 更新成功,则为true,更新失败则为false
         * @throws ArgumentError 如果 key 为null或者undefined,则引发异常
         */
        public function update(key:*, value:*):Boolean
        {
            // 检查 key 是否为 null 或 undefined
            if (key == null)
            {
                throw new ArgumentError("cannot add a value with a undefined or null key");
            }

            if (_dic[key] !== undefined && value !== undefined)
            {
                _dic[key] = value;
                return true;
            }
            return false;
        }

        /**
         * 删除由key指定的键值对. 删除成功,返回key所对应的value.如果key不存在,则删除失败,返回undefined
         *
         * @param key 将要删除的键
         * @return 删除成功,返回key所对应的value,删除失败,返回undefined
         */
        public function remove(key:*):*
        {
            var value:* = undefined;
            if (_dic[key] !== undefined)
            {
                value = _dic[key];
                delete _dic[key];
                --_length;
            }
            return value;
        }

        /**
         * 获取与key相对应的值
         *
         * @param key 指定的键
         * @return 与key对应的值
         */
        public function getValue(key:*):*
        {
            return _dic[key];
        }

        /**
         * 检测是否包含指定的key
         *
         * @param key 待检测的键
         * @return 如果存在对应的键,则返回true;否则返回false
         */
        public function hasKey(key:*):Boolean
        {
            return _dic[key] !== undefined;
        }

        /**
         * 删除所有 键值对
         */
        public function clear():void
        {
			// 方法1:稳妥,更快的垃圾回收
            //for (var key:*in _dic)
            //{
            //    delete _dic[key];
            //}
			
			// 方法2:效率高
			_dic = new Dictionary();
        }

        /**
         * 将UzHashMap中的每一个键传入指定的函数中进行处理
         *
         * @param func 处理函数
         */
        public function eachKey(func:Function):void
        {
            for (var key:*in _dic)
            {
                func(key);
            }
        }

        /**
         * 将UzHashMap中的每一个值传入指定的函数中进行处理
         *
         * @param func 处理函数
         */
        public function eachValue(func:Function):void
        {
            for each (var value:*in _dic)
            {
                func(value);
            }
        }

        //--------------------------------------------------
        //
        // properties
        //
        //--------------------------------------------------

        /**
         * UzHashMap 中存在的键值对的数量
         * @return
         */
        public function get length():int
        {
            return _length;
        }

        /**
         * UzHashMap 中存在的所有键
         * @return
         */
        public function get keys():Array
        {
            var result:Array = new Array();
            for (var key:*in _dic)
            {
                result.push(key);
            }
            return result;
        }

        /**
         * UzHashMap 中存在的所有值
         * @return
         */
        public function get values():Array
        {
            var result:Array = new Array();
            for each (var value:*in _dic)
            {
                result.push(value);
            }
            return result;
        }
        
    }
}